/*
 * Course:    CS 590 Web Services
 * Semseter:  Spring 2009
 * Professor: Sedlemeyer
 * Project:   CHEAT (Code Help Educational Assignment Tool)
 * Due Date:  May 1, 2009
 * Team:      Sarcasm
 *            (Baker, Jason; Mitchell, Robin; Shie, Keith)
 */
package cheatapp;


import cheat.administration.RepositoryStatistics;
import cheat.administration.RepositoryManagerRemote;
import cheat.assignment.AssignmentManagerRemote;
import cheat.assignment.AssignmentNotFoundException;
import cheat.assignment.InvalidAssignmentArchiveException;
import cheat.authentication.InsufficientAccessException;
import cheat.authentication.InvalidSessionException;
import cheat.authentication.NoSuchRegisteredUserException;
import cheat.authentication.SecurityManagerRemote;
import cheat.authentication.UserAlreadyRegisteredException;
import cheat.entities.AccessType;
import cheat.entities.Person;
import cheat.entities.RegisteredUser;
import cheat.administration.PopulationManagementRemote;
import edu.ipfw.cs590.cheat.services.AssignmentWrapper;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import org.web_cat._1_0.assignment_sharing.Assignment;


/**
 *
 * Author:  @author Keith Shie
 */
public class Main {
  @EJB
  private static RepositoryManagerRemote repositoryManagerBean;

  @EJB
  private static AssignmentManagerRemote assignmentManagerBean;
  @EJB
  private static PopulationManagementRemote testSessionBean;
  @EJB
  private static SecurityManagerRemote securityMgr;

  private static int RandomRunId = (int)(Math.random() * 10000 );


  private static String generateEmail( String userId, String org ){

    return userId + RandomRunId + "@" + org;
  }

  private static String generateUserId( String userId ){

    return userId + RandomRunId;
  }

  private static RegisteredUser createJason() {
    /* create a pending user */
    final Person p = new Person();

    p.setEmail( generateEmail( "safartimuro", "gmail.com" ) );
    p.setAffiliation( "IPFW" );
    p.setLastName( "Baker" );
    p.setFirstName( "Jason" );

    final RegisteredUser user = new RegisteredUser();

    user.setUserId( generateUserId("jbaker" ));
    user.setPassword( "jbaker" );
    user.setAccessCode( AccessType.FACULTY_TYPE );
    user.setPerson( p );

    return user;
  }


  private static RegisteredUser createKeith() {
    /* create a pending user */
    final Person p = new Person();

    p.setEmail( generateEmail( "caymanbumster", "gmail.com" ) );
    p.setAffiliation( "IPFW" );
    p.setLastName( "Shie" );
    p.setFirstName( "Keith" );

    final RegisteredUser user = new RegisteredUser();

    user.setUserId( generateUserId("kmshie" ) );
    user.setPassword( "kmshie" );
    user.setAccessCode( AccessType.STUDENT_TYPE );
    user.setPerson( p );

    return user;
  }


  private boolean createPending( RegisteredUser user ) throws UserAlreadyRegisteredException {

    return securityMgr.createPendingUser( user );
  }

  private byte[] getFileBytes( String zipFile ) throws IOException, FileNotFoundException {
    final File assignmentZip = new File(zipFile);
    final InputStream is = new BufferedInputStream(new FileInputStream(assignmentZip));
    int remainingBytes = (int) assignmentZip.length();
    int offset = 0;
    final byte[] assignment = new byte[remainingBytes];
    int bytesRead;
    while (remainingBytes > 0 && -1 != (bytesRead = is.read(assignment, offset, remainingBytes))) {
      remainingBytes -= bytesRead;
      offset += bytesRead;
    }
    return assignment;
  }


  private void populate() {
    /* populate database */
    testSessionBean.populateOperationalData();
  }


  private int login() {
    /* login */
    int sessId = -1;

    try {
      sessId = securityMgr.login( "sarcasm@sarcasm.org", "sarcasm" );

      System.out.println( "\nlogin: sessId = " + sessId );

    } catch ( NoSuchRegisteredUserException ex ) {
      Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getMessage() );
    }

    return sessId;
  }


  private AccessType retrieveAccessRights( int sessId ) throws InvalidSessionException {
    /* look up access level of our session */
    return securityMgr.retrieveAccessRights( sessId );
  }


  public void logout( int sessionId ) throws InvalidSessionException {
    securityMgr.logout( sessionId );
  }


  public void activatePendingUser( int sessionId, RegisteredUser pendingUser ) throws InvalidSessionException,
                                                                                      InsufficientAccessException,
                                                                                      NoSuchRegisteredUserException {
    System.out.println( "\nActivating user:" + pendingUser );

    securityMgr.activatePendingUser( sessionId,pendingUser.getPerson().getEmail());
  }


  public void denyPendingUser( int sessionId, RegisteredUser pendingUser ) throws InvalidSessionException,
                                                                                  InsufficientAccessException,
                                                                                  NoSuchRegisteredUserException {
    System.out.println( "\nDenying user:" + pendingUser );

    securityMgr.denyPendingUser( sessionId,pendingUser.getPerson().getEmail());
  }

  private void saveFileBytes(String zipFile,byte[] meta){
    OutputStream os = null;
    
    try {
      os = new BufferedOutputStream(new FileOutputStream(zipFile));

      if ( meta != null ){
        os.write(meta);
      }
    } catch ( IOException ex ){
      Logger.getLogger( Main.class.getName() ).log( Level.WARNING, "while attempting to write " + zipFile, ex );
    } finally {
      if ( os != null ){
        try {
          os.close();
        } catch (IOException ex ){}
      }
    }
  }

  private void showAssignments(String title,List<AssignmentWrapper> findResult) {
    System.out.println( title + ": size = " + findResult.size() );
    for (AssignmentWrapper aw : findResult) {
      final Assignment a = aw.extractAssignment();
      System.out.println(a.getRepository().getUuid() + ": " + a.getTitle().getContent());
    }
    System.out.println( "\n");
  }


  private void showPendingUsers( int sessId ) {
    /* get list of pending users */
    System.out.println( "\nPending users:" );
    try {
      for ( RegisteredUser u : securityMgr.getPendingUsers( sessId ) ) {
        System.out.println( "\tuserId:  " + u.getUserId() + ", email: " + u.getPerson().getEmail() );
      }
    } catch ( InvalidSessionException ex ) {
      Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getMessage() );
    } catch ( InsufficientAccessException ex ) {
      Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getMessage() );
    }
  }


  private void testStatistics() {
    final RepositoryStatistics info = repositoryManagerBean.getStatistics();

    System.out.println(info );
  }


  private int testSubmit(int facultySessId) throws InvalidSessionException, InsufficientAccessException, IOException, InvalidAssignmentArchiveException {
    int uuidSubmit = assignmentManagerBean.submitAssignment( facultySessId,
                    getFileBytes("../CheatApp/Assignments/robin_a6.zip") );

    System.out.println( "submitAssignment uuid: " + uuidSubmit );

    return  uuidSubmit;
  }


  private void testAssignments() throws IOException, NoSuchRegisteredUserException, InvalidSessionException, InvalidAssignmentArchiveException {

    final String facultyEmail = "safartimuro@gmail.com";
    int facultySessId = securityMgr.login( facultyEmail, "jbaker" );

    try {
//      final File assignmentZip = new File( "../CheatApp/Assignments/a7.zip" );

      try {
        int uuidSubmit = testSubmit( facultySessId );
        int uuidReplace1 = assignmentManagerBean.replaceAssignment( facultySessId,
                        uuidSubmit, getFileBytes("../CheatApp/Assignments/a7.zip") );

        System.out.println( "replace1 assignment uuid: " + uuidReplace1 );

        int uuidReplace2 = assignmentManagerBean.replaceAssignment( facultySessId,
                        uuidReplace1, getFileBytes("../CheatApp/Assignments/a7.zip") );

        System.out.println( "replace2 assignment uuid: " + uuidReplace2 );

        for ( String f : assignmentManagerBean.getAssignmentFileList( facultySessId, uuidReplace2)){
          System.out.println( "\t" + f );
        }

        int studentSsessId = securityMgr.login( "caymanbumster@gmail.com", "kmshie" );

        showAssignments("findByLanguage",assignmentManagerBean.getAssignmentHistory( uuidReplace2 ));

        try {
          byte[] meta1 = assignmentManagerBean.getAssignment( studentSsessId, uuidSubmit );
          saveFileBytes("dist/testStudentGet_1.zip",meta1);

          byte[] meta2 = assignmentManagerBean.getAssignment( studentSsessId, uuidReplace1 );
          saveFileBytes("dist/testStudentGet_2.zip",meta2);

          showAssignments("findByLanguage",assignmentManagerBean.findByLanguage( "Java"));
          showAssignments("findByAuthor",assignmentManagerBean.findByAuthor( "j.hacker@acm.org"));
          showAssignments("findByAuthor",assignmentManagerBean.findByAuthor( facultyEmail ));
          showAssignments("findByCourse",assignmentManagerBean.findByCourse( "CS1" ) );
        } finally {
          if ( studentSsessId != -1 ) {
            System.out.println( "logout( " + studentSsessId + " )" );
            securityMgr.logout( studentSsessId );
          }
        }
        System.out.println( "remove: " + assignmentManagerBean.removeAssignment(facultySessId, uuidSubmit) );

        byte[] a = assignmentManagerBean.getAssignment( facultySessId, uuidSubmit );

        System.out.println( "getAssignment after remove:" + (a == null ? "{not here}" : "{whoops, it's still here}") );
      } catch ( InvalidSessionException ex ) {
        Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getMessage() );
      } catch ( InsufficientAccessException ex ) {
        Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getMessage() );
      } catch (AssignmentNotFoundException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, ex.getMessage() );
      }
    } finally {
      if ( facultySessId != -1 ) {
        System.out.println( "logout( " + facultySessId + " )" );
        securityMgr.logout( facultySessId );
      }
    }
  }


  /**
   * @param args the command line arguments
   */
  public static void main( String[] args ) {
    final Main m = new Main();

    m.populate();

    int sessId = m.login();

    if ( sessId != -1 ) {
      try {
        Person p = securityMgr.getPerson( sessId, "sarcasm@sarcasm.org" );
        System.out.println( "p: " + p );
        if ( p != null ) {
          System.out.println( "p->ru: " + p.getRegisteredUser() );
        }

        for ( RegisteredUser user : new RegisteredUser[]{
            createJason(),
            createKeith()
          } ) {
          System.out.println( "\ncreate user " + user + ": " + m.createPending( user ) );
        }

        System.out.println( "\nuser access: " + m.retrieveAccessRights( sessId ) );

        m.showPendingUsers( sessId );

        try {
          List<RegisteredUser> pendingUsers = securityMgr.getPendingUsers( sessId );

          if ( pendingUsers.size() > 0 ) {
            final RegisteredUser toActivate = pendingUsers.get( 0 );

            m.activatePendingUser( sessId, toActivate );

            m.showPendingUsers( sessId );

            pendingUsers = securityMgr.getPendingUsers( sessId );

            if ( pendingUsers.size() > 0 ) {
              final RegisteredUser toDeny = pendingUsers.get( 0 );

              m.denyPendingUser( sessId, toDeny );

              m.showPendingUsers( sessId );
            }
          }
        } catch ( InvalidSessionException ex ) {
          Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getMessage() );
        } catch ( InsufficientAccessException ex ) {
          Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getMessage() );
        } catch ( NoSuchRegisteredUserException ex ) {
          Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getMessage() );
        }

        try {
            m.testAssignments();
        } catch ( InvalidAssignmentArchiveException ex ) {
          Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, null, ex );
        } catch ( IOException ex ) {
          Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getMessage() );
        } catch ( NoSuchRegisteredUserException ex ) {
          Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getMessage() );
        } catch ( InvalidSessionException ex ) {
          Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getMessage() );
        }

        m.testStatistics();

        /* log out of our session */
        System.out.println( "\nLogging out..." );
        try {
          m.logout( sessId );
        } catch ( InvalidSessionException ex ) {
          Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getMessage() );
        }

        /* Now what acess level do we have? */
        System.out.println( "\nuser access: " + m.retrieveAccessRights( sessId ) );
      } catch ( InvalidSessionException ex ) {
        Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getLocalizedMessage() );
      } catch ( InsufficientAccessException ex ) {
        Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getLocalizedMessage() );
      } catch ( UserAlreadyRegisteredException ex ) {
        Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getMessage() );
      }

      /* what happens if we log out again? */
      System.out.println( "\nLogging out again..." );
      try {
        m.logout( sessId );
      } catch ( InvalidSessionException ex ) {
        Logger.getLogger( Main.class.getName() ).log( Level.SEVERE, ex.getMessage() );
      }
    }
  }
}
